#include "modem.h"

//In lpc2378ctl.c
//extern unsigned long get_uart_clk(unsigned long n, unsigned long fosc);


#define LSR_RDR   0x01
#define LSR_OE    0x02
#define LSR_PE    0x04
#define LSR_FE    0x08
#define LSR_BI    0x10
#define LSR_THRE  0x20
#define LSR_TEMT  0x40
#define LSR_RXFE  0x80

#define U1LSR_RDR_BIT 0x00
#define U1ACR_Start_BIT 0x00

#define U1ACR_Mode_BIT 0x00

#define OSCILLATOR_CLOCK_FREQUENCY 12000000

#pragma location = "EMAC_DMA_RAM"
static char      data[MODEM_BUFFER_SIZE] = "";
#pragma location = "EMAC_DMA_RAM"
static buffer_t  cbuf;



/* Data received handler */
static void UART1_ISR(void)
{
  volatile unsigned char reg, lsr;

  while (((reg = U1IIR) & 0x01) == 0){
    switch (reg & ((1<<IIR1) | (1<<IIR2) | (1<<IIR3))){
      case (1<<IIR1) | (1<<IIR2): // Received line status
        lsr = U1LSR;
        if (lsr & ((LSR_OE|LSR_PE|LSR_FE|LSR_RXFE|LSR_BI))){
          //error
          U1RBR;
        }
        else if (lsr & LSR_RDR) {
          while (U1LSR & (1<<U1LSR_RDR_BIT)) {
            unsigned char c = U1RBR;
            buffer_put(&cbuf, c);
          }
        }
      break;
      case (1<<IIR2):             // Receive Data Available
      case (1<<IIR2) | (1<<IIR3): // Character Timeout Indicator
        while (U1LSR & (1<<U1LSR_RDR_BIT)){
          unsigned char c = U1RBR;
          buffer_put(&cbuf, c);
        }
      break;
      default:                    // Other
        U1LSR;
        U1RBR;
        U1MSR;
    }
  }
}

/* Initialize SIM300 modem with any baud: 0(autobaud), 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 */
void modem_init(unsigned int baud)
{
  cbuf = buffer_create(data, MODEM_BUFFER_SIZE); 

  /* Set UART1 data mode and set divisor latch. 
  (* 083H - 8 bits, no parity, 1 stop bit *)
  (* 087H - 8 bits, no parity, 2 stop bits */
  //U1LCR = 0x80;
   U1LCR = 0x80;
  
  



  /* Clear Divisor Latch */
  U1LCR = 0x03;

  /* Enable FIFO and set 8 bytes buffer */
  U1FCR = 0x81;
    
  /* Enable automatic RTS and CTS signals (hardware flow control) 
     RTSen bit 6, CTSen bit 7 */
  U1MCR = 0x80;
            
  /* Configure the Vectored Interrupt Controller */
  /* Install UART1 handler */
 // ctl_set_isr(VICIntSelect_UART1_BIT, 7, CTL_ISR_TRIGGER_FIXED, UART1_ISR, 0);
  /* Enable UART1 interrupt */
 // ctl_unmask_isr(VICIntSelect_UART1_BIT);
  /* Enable interrupts */
 // ctl_global_interrupts_enable();

  /* Enable data receive interrupt */
 // U1IER = (1<<U1IER_RBR_Interrupt_Enable_BIT);   
}

/* Turn on internal loopback mode */
void modem_loopbackon()
{
 // U0MCR =  0x0D0;
}
  
/* Turn off internal loopback mode */
void modem_loopbackoff()
{
 // U0MCR =  0x0C0;
}

int  modem_available()
{
  return cbuf.available;
}

int modem_read(char* dest, int length)
{
  int available = modem_available();
  int min = (length < available) ? (length) : (available);
  for (int i = 0; i < min; i++)
  {
  //  dest[i] = buffer_get(&cbuf);
  }
  return min;
}


void modem_putc(char c)
{
  //TODO: Add exit counter
  //while (!(U1LSR & 0x60));
  unsigned int i = 0;
  while (!(U1LSR & 0x20))
    if (i++ > 0x100000) 
      break;
  U1THR = c;

}

void modem_putcx(char c)
{
  //TODO: Add exit counter
  //while (!(U1LSR & 0x60));
  unsigned int i = 0;
  while (!(U0LSR & 0x20))
    if (i++ > 0x100000) 
      break;
  U0THR = c;

}

void modem_debug(char *str)
{
  while(*str) modem_putcx(*str++);
}


void modem_puts(char *str)
{
  while(*str) modem_putc(*str++);
}

void modem_putn(char *str, int len)
{
  for (int i = 0; i < len; i++) modem_putc(str[i]);
}

void modem_flush()
{
 // buffer_flush(&cbuf);
}

void DelayS (unsigned long a) 				
{
 	while (--a!=0);            				
}